package sbc.group1.lab1.mozartspaces;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.mozartspaces.capi3.AnyCoordinator;
import org.mozartspaces.capi3.Coordinator;
import org.mozartspaces.core.Capi;
import org.mozartspaces.core.DefaultMzsCore;
import org.mozartspaces.core.MzsConstants;
import org.mozartspaces.core.MzsCoreException;
import org.mozartspaces.core.TransactionReference;
import org.mozartspaces.core.MzsConstants.RequestTimeout;
import org.mozartspaces.core.config.CommonsXmlConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


class SpaceServer extends Space {
    
    private static final Logger log = LoggerFactory.getLogger(SpaceServer.class);
    
    public static void main(String args[]) throws MalformedURLException, MzsCoreException {

        SpaceServer server = new SpaceServer();
        server.init(
                new File(args[0]).toURI().toURL());
        while(true) {
            synchronized (Thread.currentThread()) {
                try {
                    Thread.currentThread().wait();
                } catch (InterruptedException e) {
                    return;
                }
            }
        }
    }
    
    public void init(URL configUrl) throws MzsCoreException {
        core = DefaultMzsCore.newInstance(CommonsXmlConfiguration.loadFrom(configUrl));
        capi = new Capi(core);
        
        TransactionReference transaction = capi.createTransaction(
                RequestTimeout.INFINITE, (URI)null);
        
        
        assembledCarContainer =  capi.createContainer(ASSEMBLED_CAR_CONTAINER_NAME,
                (URI)null,MzsConstants.Container.UNBOUNDED, transaction, new CarCoordinator());
        completedCarContainer =  capi.createContainer(COMPLETED_CAR_CONTAINER_NAME,
                (URI)null,MzsConstants.Container.UNBOUNDED, transaction, new CarCoordinator());
        completenessTestedContainer =  capi.createContainer(COMPLETENESS_TESTED_CONTAINER_NAME,
                (URI)null,MzsConstants.Container.UNBOUNDED, transaction, new CarCoordinator());
        defectsTestedContainer =  capi.createContainer(DEFECTS_TESTED_CONTAINER_NAME,
                (URI)null,MzsConstants.Container.UNBOUNDED, transaction, new CarCoordinator());
        testedCarContainer = capi.createContainer(TESTED_CAR_CONTAINER_NAME,
                (URI)null,MzsConstants.Container.UNBOUNDED, transaction,
                new CarCoordinator());
        finishedCarContainer = capi.createContainer(FINISHED_CAR_CONTAINER_NAME,
                (URI)null,MzsConstants.Container.UNBOUNDED, transaction);
        defectCarContainer = capi.createContainer(DEFECT_CAR_CONTAINER_NAME,
                (URI)null,MzsConstants.Container.UNBOUNDED, transaction);
        orderJobsReissueContainer = capi.createContainer(ORDER_JOB_REISSUE_CONTAINER_NAME,
                (URI)null,MzsConstants.Container.UNBOUNDED, transaction);
        
        
        AutogeneratedIdContainerAspect partIdAspect = new AutogeneratedIdContainerAspect();
        
        List<Coordinator> obligatory = new ArrayList<Coordinator>();
        List<Coordinator> optional = new ArrayList<Coordinator>();
        obligatory.add( new AnyCoordinator());
        obligatory.add(LabelCoatablesContainerAspect.getCoordinator());
        optional.add(new ColorCoordinator());
        carBodyContainer = capi.createContainer(CAR_BODY_CONTAINER_NAME,
                (URI)null,MzsConstants.Container.UNBOUNDED, 
               obligatory, optional, transaction);
        capi.addContainerAspect(partIdAspect, 
                carBodyContainer,
                partIdAspect.getUsedContainerIPoints(),
                transaction);
        capi.addContainerAspect(new LabelCoatablesContainerAspect(), 
                carBodyContainer,
                LabelCoatablesContainerAspect.getUsedContainerIPoints(),
                transaction);
        
        obligatory = new ArrayList<Coordinator>();
        obligatory.add( new AnyCoordinator());
        obligatory.add(LabelEnginesContainerAspect.getCoordinator());
        optional = null;
        engineContainer = capi.createContainer(ENGINE_CONTAINER_NAME,
                (URI)null,MzsConstants.Container.UNBOUNDED,
                obligatory, optional, transaction);
        capi.addContainerAspect(partIdAspect, 
                engineContainer,
                partIdAspect.getUsedContainerIPoints(),
                transaction);
        capi.addContainerAspect(new LabelEnginesContainerAspect(), 
                engineContainer,
                LabelEnginesContainerAspect.getUsedContainerIPoints(),
                transaction);
        
        wheelContainer = capi.createContainer(WHEEL_CONTAINER_NAME,
                (URI)null,MzsConstants.Container.UNBOUNDED, transaction);
        capi.addContainerAspect(partIdAspect, 
                wheelContainer,
                partIdAspect.getUsedContainerIPoints(),
                transaction);
        
        AutogeneratedIdContainerAspect orderIdAspect = new AutogeneratedIdContainerAspect();
        orderIndexContainer = capi.createContainer(ORDER_INDEX_CONTAINER_NAME,
                (URI)null,MzsConstants.Container.UNBOUNDED, transaction);
        capi.addContainerAspect(orderIdAspect, 
                orderIndexContainer,
                orderIdAspect.getUsedContainerIPoints(),
                transaction);
        
        orderContainer = capi.createContainer(ORDER_CONTAINER_NAME,
                (URI)null,MzsConstants.Container.UNBOUNDED, transaction,
                new OrderCoordinator());
        
        capi.commitTransaction(transaction);
        log.info("Space is up.");
    }
    
    public void shutdown() {
        try {
            capi.destroyContainer(assembledCarContainer, null);
            capi.destroyContainer(completedCarContainer, null);
            capi.destroyContainer(testedCarContainer, null);
            capi.destroyContainer(finishedCarContainer, null);
            capi.destroyContainer(defectCarContainer, null);
            capi.destroyContainer(carBodyContainer, null);
            capi.destroyContainer(engineContainer, null);
            capi.destroyContainer(wheelContainer, null);
            capi.destroyContainer(orderContainer, null);
            //TODO destroy dynamic containers
        } catch (MzsCoreException e) {
            log.warn("Destroying container failed.",e);
        }
        
        core.shutdown(false);
    }

    @Override
    public URI getSpaceUri() {
        return null;
    }
}
